/*
*   Packet.c
*   Authors:
*   Contains information that is nessecary for the UI to update.
*/
#include <stdlib.h>
#include "Packet.h"

PacketPtr packetConstructor(int type, int requestID, int runningProcess, int kb, QueuePtr rq, IODevicePtr* devices, MutexPtr* mutexes, CVPtr* condVars, int numProducerConsumer) {
    PacketPtr this = (PacketPtr) malloc(sizeof(PacketStr));
    this->type = type;
    this->requestID = requestID;
    this->consumersValue = NO_ID;
    this->runningProcess = runningProcess;
    this->keyBoard = kb;
    this->numProducerConsumer = numProducerConsumer;

    this->readyQueue = (int*) malloc(sizeof(int) * rq->size);
    populateReadyQueue(this, rq);
    this->readyQueueSize = rq->size;


    //generate device queues
    this->deviceQueues = (int**) malloc(sizeof(int*) * NUM_IO);

    int i = 0;
    for(; i < NUM_IO; i++) {
        int theSize = sizeof(int) * IO_QUEUE_SIZE;
        this->deviceQueues[i] = (int*) malloc(theSize);
    }
    populateDeviceQueue(this, devices);

    //generate mutex queues
    this->mutexQueues = (int**) malloc(sizeof(int*) * numProducerConsumer);
    this->mutexOwners = (int*) malloc(sizeof(int) * numProducerConsumer);
    i = 0;
    for(; i < numProducerConsumer; i++) {
        int theSize = sizeof(int) * IO_QUEUE_SIZE;
        this->mutexQueues[i] = (int*) malloc(theSize);
    }
    populateMutexQueues(this, mutexes);

    //generate condition variable queues
    this->conditionQueues = (int**) malloc(sizeof(int*) * numProducerConsumer* 2);
    i = 0;
    for(; i < numProducerConsumer*2; i++) {
        int theSize = sizeof(int) * IO_QUEUE_SIZE;
        this->conditionQueues[i] = (int*) malloc(theSize);
    }
    populateConditionQueues(this, condVars);

    this->destruct = packetDestructor;
    return this;
}


void packetDestructor(PacketPtr this) {
    int i = 0;

    for(; i < NUM_IO; i++) {    //free io arrays
        free(this->deviceQueues[i]);
    }
    free(this->deviceQueues);

    i = 0;
    for(; i < this->numProducerConsumer; i++) { //free the mutex arrays
        free(this->mutexQueues[i]);
    }
    free(this->mutexQueues);
    free(this->mutexOwners);

    i = 0;
    for(; i < this->numProducerConsumer*2; i++) { //free the condition variable arrays
        free(this->conditionQueues[i]);
    }
    free(this->conditionQueues);

    free(this->readyQueue);
    free(this);
}

/*
*   pull the device numbers out of the the io device's queues & store them
*   in our 2d int array.
*/
void populateDeviceQueue(PacketPtr this, IODevicePtr* devices) {
    //this->deviceQueues
    int i = 0;
    for(; i < NUM_IO; i++) {//when node == null we are done
        int index = 0;
        NodePtr current = devices[i]->ioQueue->head;//get the head node from the io devicequeue
        while(current != (NodePtr) NULL) {
            this->deviceQueues[i][index] = current->contents->pid;//store the value in our array
            current = current->next;//get the next node
            index++;
        }

        this->deviceQueues[i][index] = NO_ID;  //terminate the array, so we know where the end is.
    }
}

/*
*   pull the id's out of the ready queue & load them into the array for updating the gui.
*/
void populateReadyQueue(PacketPtr this, QueuePtr rq) {
    int i = 0;
    NodePtr current;
    current = rq->head;
    for(; i < rq->size; i++) {

        this->readyQueue[i] = current->contents->pid;
        current = current->next;
    }
}

/**
*   pull the id's out of the ready queue & load them into the array for updating the gui.
*/
void populateMutexQueues(PacketPtr this, MutexPtr* mutexes) {
    int i = 0;
    for(; i < this->numProducerConsumer; i++) {//when node == null we are done
        int index = 0;
        NodePtr current = mutexes[i]->processQueue->head;//get the head node from the io devicequeue
        this->mutexOwners[i] = mutexes[i]->owner;//set the owners
        while(current != (NodePtr) NULL) {
            this->mutexQueues[i][index] = current->contents->pid;//store the value in our array
            current = current->next;//get the next node
            index++;
        }
        this->mutexQueues[i][index] = NO_ID;  //terminate the array, so we know where the end is.
    }
}

void populateConditionQueues(PacketPtr this, CVPtr* condVars) {
    int i = 0;
    for(; i < this->numProducerConsumer * 2; i++) {//when node == null we are done
        int index = 0;
        NodePtr current = condVars[i]->waitingQueue->head;//get the head node from the io devicequeue
        while(current != (NodePtr) NULL) {
            this->conditionQueues[i][index] = current->contents->pid;//store the value in our array
            current = current->next;//get the next node
            index++;
        }
        this->conditionQueues[i][index] = NO_ID;  //terminate the array, so we know where the end is.
    }


}

